package net.gazhi.delonix.core.service;

import net.gazhi.delonix.core.ClassUtils;
import net.gazhi.delonix.core.entity.TreeNode;

import org.hibernate.Criteria;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

/**
 * 普通树节点的业务逻辑类<br>
 * 封装了对数据库的一些通用操作，可以聚合到实体类使用
 * 
 * @author Jeffrey Lin
 *
 */
@Service
public class SimpleTreeNodeService extends AbstractService {

	/**
	 * 更新节点以及下级节点的 fullId 和 fullOrder
	 * 
	 * @param node
	 */
	public void updateFullIdAndOrder(TreeNode node) {
		TreeNode parent = node.getParent();
		if (parent != null) {
			node.setFullOrder(parent.getFullOrder() + "_" + String.format("%06d", node.getShowOrder()));
			node.setFullId(parent.getFullId() + "_" + node.getId());
			dao.update(node);
		} else {
			node.setFullOrder(String.format("%06d", node.getShowOrder()));
			node.setFullId(String.valueOf(node.getId()));
		}
		if (node.getChildren() != null) {
			for (TreeNode n : node.getChildren()) {
				this.updateFullIdAndOrder(n);
			}
		}
	}

	/**
	 * 生成下一个序号
	 * 
	 * @param node
	 * @param entityCass
	 * @return
	 */
	public int generateOrder(TreeNode node) {
		Criteria query = createCriteria(node.getClass()).setProjection(Projections.max("showOrder"));
		query.add(node.getParent() == null ? Restrictions.isNull("parent.id") : Restrictions.eq("parent.id", node.getParent().getId()));
		Integer order = (Integer) query.uniqueResult();
		return order == null ? 1 : order + 1;
	}

	/**
	 * 判断是否存在下级实体
	 * 
	 * @param node
	 * @param childEtityCass
	 * @return
	 */
	public boolean existChild(TreeNode node, Class<? extends TreeNode> childEtityCass) {
		return createCriteria(childEtityCass).setProjection(Projections.id()).add(Restrictions.eq("parent.id", node.getId())).setMaxResults(1).uniqueResult() != null;
	}

	/**
	 * 移动位置
	 * 
	 * @param node
	 * @param target
	 * @param moveType
	 * @return
	 */
	@Transactional
	public boolean move(TreeNode node, TreeNode target, String moveType) {
		// 参数值基本检查
		if (node == null || target == null || !("inner".equals(moveType) || "prev".equals(moveType) || "next".equals(moveType))) {
			return false;
		}
		// 避免成环
		if (StringUtils.startsWithIgnoreCase(target.getFullId(), node.getFullId())) {
			return false;
		}
		// 不允许与根节点同级
		if (target.getParent() == null && !"inner".equals(moveType)) {
			return false;
		}

		// 内部插入
		if ("inner".equals(moveType)) {
			// 查找同类型的排序编号
			node.setParent(target);
			node.setShowOrder(this.generateOrder(node));
			this.updateFullIdAndOrder(node);

			// 前后同级插入
		} else {

			// 类型一致才能在前面或后面插入
			if (!ClassUtils.getPersistentClassOfLazy(target).equals(ClassUtils.getPersistentClassOfLazy(node))) {
				return false;
			}

			int showOrder = target.getShowOrder() + ("prev".equals(moveType) ? 0 : 1);
			// 更新同级的后面的元素的序号
			Criteria query = createCriteria(node.getClass()).add(Restrictions.eq("parent.id", target.getParent().getId())).add(Restrictions.ge("showOrder", showOrder));
			for (Object obj : query.list()) {
				TreeNode n = (TreeNode) obj;
				n.setShowOrder(n.getShowOrder() + 1);
				this.updateFullIdAndOrder(n);
			}
			node.setParent(target.getParent());
			node.setShowOrder(showOrder);
			this.updateFullIdAndOrder(node);
		}
		return true;
	}
}
